package vectors;

import Exceptions.IncompatibleVectorSizesException;
import Thread.ClassForVectors;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Vectors {

    private static VectorFactory vecFac = new ArrayVectorFactory();

    public static void setVectorFactory(VectorFactory fact) {
        vecFac = fact;

    }

    public static VectorIn createInstance() {
        return vecFac.factoryMethod();
    }

    public static VectorIn createInstance(int length) {
        return vecFac.factoryMethod(length);
    }

    public static VectorIn createInstance(int length, VectorIn vector) {
        try {
            Class cl = vector.getClass();
            Class[] constructor = {Integer.TYPE};
            Constructor c = cl.getConstructor(constructor);
            Object obj = c.newInstance(length);
            return (VectorIn) obj;
        } catch (NoSuchMethodException ex) {
            System.out.println(ex.getMessage());
            return createInstance(length);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
            return null;
        }
    }

    static public VectorIn getAdaptedJVector(java.util.Vector JVector) {
        VectorIn temp = new JVectorAdapter(JVector);
        return temp;
    }

    static public VectorIn getProtectedVector(VectorIn vector) {
        VectorIn temp = new ProtectedVector(vector);
        return temp;
    }

    static public VectorIn multiplyVector(VectorIn Vector, double multiply) {
        VectorIn temp = createInstance(Vector.getSize(), Vector);
        for (int i = 0; i < Vector.getSize(); i++) {
            temp.setElement(Vector.getElement(i) * multiply, i);
        }
        return temp;
    }

    static public VectorIn vectorPlusVector(VectorIn Vector, VectorIn Vector1) throws IncompatibleVectorSizesException {
        VectorIn temp = createInstance(Vector.getSize(), Vector);
        temp.objectToVector(Vector);
        temp.vectorPlusVector(Vector1);
        return temp;

    }

    static public VectorIn generateRandom(int length, int max, int min) {
        VectorIn nvec = createInstance(length);
        for (int i = 0; i < length; i++) {
            nvec.setElement(min + Math.random() * (max - min), i);
        }
        return nvec;
    }

    static public void sort(VectorIn Vector) {
        double p;
        for (int i = 0; i < Vector.getSize() - 1; i++) {
            for (int j = i + 1; j < Vector.getSize(); j++) {
                if (Vector.getElement(i) > Vector.getElement(j)) {
                    p = Vector.getElement(i);
                    Vector.setElement(Vector.getElement(j), i);
                    Vector.setElement(p, j);
                }
            }
            System.out.println(Vector.getElement(i));
        }

    }

    public static void outputVector(VectorIn Vector, OutputStream o) throws IOException {
        DataOutputStream data = new DataOutputStream(o);
        int size = Vector.getSize();
        data.writeInt(size);
        for (int i = 0; i < Vector.getSize(); i++) {
            data.writeDouble(Vector.getElement(i));
        }
    }

    public static VectorIn inputVector(InputStream in) throws IOException {
        VectorIn vec = null;
        DataInputStream data = new DataInputStream(in);
        int length = data.readInt();
        VectorIn temp = createInstance();
        for (int i = 0; i < length; i++) {
            temp.add(data.readDouble());
        }
        vec = createInstance();
        vec.objectToVector(temp);

        return vec;
    }

    public static void writeVector(VectorIn vector, Writer out) throws IOException {
        PrintWriter pw = new PrintWriter(out);
        int length = vector.getSize();
        pw.print(length + " ");
        for (int i = 0; i < vector.getSize(); i++) {
            pw.print(vector.getElement(i) + " ");
        }
        pw.println();
        pw.flush();

    }

    public static VectorIn readVector(Reader in) throws IOException {
        VectorIn vec = null;
        StreamTokenizer t = new StreamTokenizer(in);
        t.nextToken();
        int length = (int) t.nval;
        double[] tempValues = new double[length];
        for (int i = 0; i < length; i++) {
            t.nextToken();
            tempValues[i] = t.nval;
            //System.out.println(tempValues[i]);
        }
        vec = createInstance();
        vec.massiveToVector(tempValues);
        return vec;
    }

    public static VectorIn synchronizedVector(VectorIn vector) {
        VectorIn temp = new ClassForVectors(vector);
        return temp;
    }
}